package tasks.io.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tasks.io.core.*;
import tasks.io.core.lock.SetWithLock;
import tasks.io.core.thread.SynThreadPoolExecutor;

import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;


public class TioServerConfig extends TioConfig {
    static Logger log = LoggerFactory.getLogger(TioServerConfig.class);
    private AcceptCompletionHandler acceptCompletionHandler = null;
    private TioServerHandler tioServerHandler = null;
    private TioServerListener tioServerListener = null;
    private Thread checkHeartbeatThread = null;
    private boolean needCheckHeartbeat = true;
    //	private static Set<TioServerConfig>	SHARED_SET				= null;
    private boolean isShared = false;


    public TioServerConfig(TioServerHandler tioServerHandler, TioServerListener tioServerListener) {
        this(null, tioServerHandler, tioServerListener);
    }


    public TioServerConfig(String name, TioServerHandler tioServerHandler, TioServerListener tioServerListener) {
        this(name, tioServerHandler, tioServerListener, null, null);
    }


    public TioServerConfig(TioServerHandler tioServerHandler, TioServerListener tioServerListener, SynThreadPoolExecutor tioExecutor, ThreadPoolExecutor groupExecutor) {
        this(null, tioServerHandler, tioServerListener, tioExecutor, groupExecutor);
    }

    public TioServerConfig(String name, TioServerHandler tioServerHandler, TioServerListener tioServerListener, SynThreadPoolExecutor tioExecutor,
                           ThreadPoolExecutor groupExecutor) {
        super(tioExecutor, groupExecutor);


        init(name, tioServerHandler, tioServerListener, tioExecutor, groupExecutor);
    }


    private void init(String name, TioServerHandler tioServerHandler, TioServerListener tioServerListener, SynThreadPoolExecutor tioExecutor, ThreadPoolExecutor groupExecutor) {
        this.name = name;
        this.groupStat = new ServerGroupStat();
        this.acceptCompletionHandler = new AcceptCompletionHandler();
        this.tioServerHandler = tioServerHandler;
        this.tioServerListener = tioServerListener;// == null ? new DefaultTioServerListener() : tioServerListener;
        checkHeartbeatThread = new Thread(new Runnable() {
            @Override
            public void run() {
                //第一次先休息一下
                try {
                    Thread.sleep(1000 * 10);
                } catch (InterruptedException e1) {
                    log.error(e1.toString(), e1);
                }

                while (needCheckHeartbeat && !isStopped()) {
                    //					long sleeptime = heartbeatTimeout;
                    if (heartbeatTimeout <= 0) {
                        log.info("{}, 用户取消了框架层面的心跳检测，如果业务需要，请用户自己去完成心跳检测", TioServerConfig.this.name);
                        break;
                    }
                    try {
                        Thread.sleep(heartbeatTimeout);
                    } catch (InterruptedException e1) {
                        log.error(e1.toString(), e1);
                    }
                    long start = SystemTimer.currTime;
                    SetWithLock<ChannelContext> setWithLock = TioServerConfig.this.connections;
                    Set<ChannelContext> set = null;
                    long start1 = 0;
                    int count = 0;
                    ReadLock readLock = setWithLock.readLock();
                    readLock.lock();
                    try {
                        start1 = SystemTimer.currTime;
                        set = setWithLock.getObj();

                        for (ChannelContext channelContext : set) {
                            count++;
                            long compareTime = Math.max(channelContext.channelStat.latestTimeOfReceivedByte, channelContext.channelStat.latestTimeOfSentPacket);
                            long currtime = SystemTimer.currTime;
                            long interval = currtime - compareTime;

                            boolean needRemove = false;
                            if (channelContext.heartbeatTimeout != null && channelContext.heartbeatTimeout > 0) {
                                needRemove = interval > channelContext.heartbeatTimeout;
                            } else {
                                needRemove = interval > heartbeatTimeout;
                            }

                            if (needRemove) {
                                if (!TioServerConfig.this.tioServerListener.onHeartbeatTimeout(channelContext, interval, channelContext.channelStat.heartbeatTimeoutCount.incrementAndGet())) {
                                    log.info("{}, {} ms没有收发消息", channelContext, interval);
                                    channelContext.setCloseCode(CloseCode.HEARTBEAT_TIMEOUT);
                                    Io.remove(channelContext, interval + " ms没有收发消息");
                                }
                            }
                        }
                    } catch (Throwable e) {
                        log.error("", e);
                    } finally {
                        try {
                            readLock.unlock();
                            if (debug) {
                                StringBuilder builder = new StringBuilder();
                                builder.append(SysConst.CRLF).append(TioServerConfig.this.getName());
                                builder.append("\r\n ├ 当前时间:").append(SystemTimer.currTime);
                                builder.append("\r\n ├ 连接统计");
                                builder.append("\r\n │ \t ├ 共接受过连接数  :").append(((ServerGroupStat) groupStat).accepted.get());
                                builder.append("\r\n │ \t ├ 当前连接数            :").append(set.size());
                                //								builder.append("\r\n │ \t ├ 当前群组数            :").append(groups);

                                builder.append("\r\n │ \t └ 关闭过的连接数  :").append(groupStat.closed.get());

                                builder.append("\r\n ├ 消息统计");
                                builder.append("\r\n │ \t ├ 已处理消息  :").append(groupStat.handledPackets.get());
                                builder.append("\r\n │ \t ├ 已接收消息(packet/byte):").append(groupStat.receivedPackets.get()).append("/").append(groupStat.receivedBytes.get());
                                builder.append("\r\n │ \t ├ 已发送消息(packet/byte):").append(groupStat.sentPackets.get()).append("/").append(groupStat.sentBytes.get()).append("b");
                                builder.append("\r\n │ \t ├ 平均每次TCP包接收的字节数  :").append(groupStat.getBytesPerTcpReceive());
                                builder.append("\r\n │ \t └ 平均每次TCP包接收的业务包  :").append(groupStat.getPacketsPerTcpReceive());
                                builder.append("\r\n └ IP统计时段 ");


                                builder.append("\r\n ├ 节点统计");
                                builder.append("\r\n │ \t ├ clientNodes :").append(TioServerConfig.this.clientNodes.getObjWithLock().getObj().size());
                                builder.append("\r\n │ \t ├ 所有连接               :").append(TioServerConfig.this.connections.getObj().size());

                                builder.append("\r\n │ \t └ 等待同步消息响应 :").append(TioServerConfig.this.waitingResps.getObj().size());


                                log.warn(builder.toString());

                                long end = SystemTimer.currTime;
                                long iv1 = start1 - start;
                                long iv = end - start1;
                                log.warn("{}, 检查心跳, 共{}个连接, 取锁耗时{}ms, 循环耗时{}ms, 心跳超时时间:{}ms", TioServerConfig.this.name, count, iv1, iv, heartbeatTimeout);
                            }
                        } catch (Throwable e) {
                            log.error("", e);
                        }
                    }
                }

                //log.error(name + "--" + needCheckHeartbeat + "-" + isStopped() + "--执行完成了---------------------------------------------------------------------------------------------------执行完成了");
            }
        }, "tio-timer-checkheartbeat-" + id + "-" + name);
        checkHeartbeatThread.setDaemon(true);
        checkHeartbeatThread.setPriority(Thread.MIN_PRIORITY);
        checkHeartbeatThread.start();
    }


    public AcceptCompletionHandler getAcceptCompletionHandler() {
        return acceptCompletionHandler;
    }


    @Override
    public TioHandler getTioHandler() {
        return this.getTioServerHandler();
    }


    @Override
    public TioListener getTioListener() {
        return getTioServerListener();
    }

    /**
     * @return the tioServerHandler
     */
    public TioServerHandler getTioServerHandler() {
        return tioServerHandler;
    }

    /**
     * @return the tioServerListener
     */
    public TioServerListener getTioServerListener() {
        return tioServerListener;
    }

    public void setTioServerListener(TioServerListener tioServerListener) {
        this.tioServerListener = tioServerListener;
    }

    /**
     * @return
     * @author tanyaowu
     */
    @Override
    public boolean isServer() {
        return true;
    }

    @Override
    public String toString() {
        return "TioServerConfig [name=" + name + "]";
    }

    public void share(TioServerConfig tioConfig) {
        synchronized (TioServerConfig.class) {
            if (tioConfig == this) {
                return;
            }
            this.clientNodes = tioConfig.clientNodes;
            this.connections = tioConfig.connections;

            this.groupStat = tioConfig.groupStat;


            if (!tioConfig.isShared && !this.isShared) {
                this.needCheckHeartbeat = false;
            }
            if (tioConfig.isShared && !this.isShared) {
                this.needCheckHeartbeat = false;
            }
            if (!tioConfig.isShared && this.isShared) {
                tioConfig.needCheckHeartbeat = false;
            }

            //下面这两行代码要放到前面if的后面
            tioConfig.isShared = true;
            this.isShared = true;

            //			if (SHARED_SET == null) {
            //				SHARED_SET = new HashSet<>();
            //			}
            //
            //			SHARED_SET.add(this);
            //			SHARED_SET.add(tioConfig);
            //
            //			boolean need = true;
            //			for (TioServerConfig gc : SHARED_SET) {
            //				if (!need) {
            //					gc.needCheckHeartbeat = false;
            //					continue;
            //				}
            //
            //				if (gc.needCheckHeartbeat) {
            //					need = false;
            //				}
            //			}
        }
    }

}
